package net.nohaven.proj.javeau.crypt.engine;

/**
 * The Phelix implementation, based on the original PhelixJ package by
 * Markus Hahn.
 **/
public class Phelix {
	public static final int MODE_ENCRYPT = 0;
	public static final int MODE_DECRYPT = 1;

	public final static int PHELIX_MAC_SIZE = 128;
	public final static int PHELIX_MAC_SIZE_96 = 96;

	private final static int PHELIX_NONCE_SIZE = 128;
	private final static int PHELIX_NONCE_SIZE_BYTES = PHELIX_NONCE_SIZE >> 3;

	private final static int PHELIX_KEY_SIZE = 256;
	private final static int PHELIX_KEY_SIZE_BYTES = PHELIX_KEY_SIZE >> 3;

	private final static int PHELIX_DATA_ALIGN = 4;

	private final static int MAC_INIT_CNT = 8;
	private final static int MAC_WORD_CNT = PHELIX_MAC_SIZE / 32;

	private final static int ROT_0a = 9;
	private final static int ROT_1a = 10;
	private final static int ROT_2a = 17;
	private final static int ROT_3a = 30;
	private final static int ROT_4a = 13;

	private final static int ROT_0b = 20;
	private final static int ROT_1b = 11;
	private final static int ROT_2b = 5;
	private final static int ROT_3b = 15;
	private final static int ROT_4b = 25;

	private final static int MAC_MAGIC_XOR = 0x912d94f1;
	private final static int AAD_MAGIC_XOR = 0xaadaadaa;

	private final static int[] MASK_LEFTOVER = { 0, 0x00ff, 0x00ffff,
			0x00ffffff };

	private int ks_macSize;
	private int ks_X_1_bump;
	private int[] ks_X_0 = new int[8];
	private int[] ks_X_1 = new int[8];

	private int[] cs_oldZ = new int[4];
	private int[] cs_Z = new int[5];
	private int cs_i;
	private long cs_aadLen;
	private long cs_msgLen;
	private int cs_aadXor;

	private int[] cache_finalize_tmp = new int[MAC_INIT_CNT + MAC_WORD_CNT];
	private int[] cache_processbytes_buckets = new int[2];
	private int bucketIdx;

	public Phelix(int macSize) {
		this.ks_macSize = macSize;
		reset();
	}

	public void reset() {
		this.cs_i = 0;
		this.cs_msgLen = 0;
	}

	public void setupKey(int mode, byte[] key) throws IllegalArgumentException {
		int i, k, keyOfs, rep, tmp;
		int Z_0, Z_1, Z_2, Z_3, Z_4;

		this.bucketIdx = mode;

		int[] X = this.ks_X_0;

		if (key.length != PHELIX_KEY_SIZE_BYTES)
			throw new IllegalArgumentException("invalid key size " + key.length);

		this.ks_X_1_bump = (PHELIX_KEY_SIZE_BYTES >>> 1)
				+ ((this.ks_macSize % PHELIX_MAC_SIZE) << 8);

		tmp = (PHELIX_KEY_SIZE_BYTES + 31) >>> 5;

		for (keyOfs = 0, i = 0; i < tmp; keyOfs += 4, i++)
			X[i] = ((int) key[0] & 0x0ff)
					| (((int) key[keyOfs + 1] & 0x0ff) << 8)
					| (((int) key[keyOfs + 2] & 0x0ff) << 16)
					| (((int) key[keyOfs + 3] & 0x0ff) << 24);

		for (; i < 8; i++) {
			X[i] = 0;
		}

		if (0 != (0x1f & PHELIX_KEY_SIZE_BYTES))
			X[PHELIX_KEY_SIZE_BYTES >>> 5] &= ((PHELIX_KEY_SIZE_BYTES & 0x1f) << 1) - 1;

		tmp = (PHELIX_KEY_SIZE_BYTES >>> 3) + 64;

		for (i = 0; i < 8; i++) {
			k = (i & 1) << 2;

			Z_0 = X[k];
			Z_1 = X[k + 1];
			Z_2 = X[k + 2];
			Z_3 = X[k + 3];
			Z_4 = tmp;

			for (rep = 0; rep < 2; rep++) {
				Z_0 += Z_3;
				Z_3 = Integer.rotateLeft(Z_3, ROT_3b);
				Z_1 += Z_4;
				Z_4 = Integer.rotateLeft(Z_4, ROT_4b);
				Z_2 ^= Z_0;
				Z_0 = Integer.rotateLeft(Z_0, ROT_0a);
				Z_3 ^= Z_1;
				Z_1 = Integer.rotateLeft(Z_1, ROT_1a);
				Z_4 += Z_2;
				Z_2 = Integer.rotateLeft(Z_2, ROT_2a);

				Z_0 ^= Z_3;
				Z_3 = Integer.rotateLeft(Z_3, ROT_3a);
				Z_1 ^= Z_4;
				Z_4 = Integer.rotateLeft(Z_4, ROT_4a);
				Z_2 += Z_0;
				Z_0 = Integer.rotateLeft(Z_0, ROT_0b);
				Z_3 += Z_1;
				Z_1 = Integer.rotateLeft(Z_1, ROT_1b);
				Z_4 ^= Z_2;
				Z_2 = Integer.rotateLeft(Z_2, ROT_2b);
			}

			k = (k + 4) & 7;

			X[k] ^= Z_0;
			X[k + 1] ^= Z_1;
			X[k + 2] ^= Z_2;
			X[k + 3] ^= Z_3;
		}
	}

	public void setupNonce(byte[] nonce) throws IllegalArgumentException {
		int i, j, n, nonceOfs;
		int[] X_0, X_1, oldZ, Z;
		int X_1_bump;
		int Z_0, Z_1, Z_2, Z_3, Z_4;

		if (nonce.length != PHELIX_NONCE_SIZE_BYTES)
			throw new IllegalArgumentException("invalid nonce size"
					+ nonce.length);

		X_0 = this.ks_X_0;
		X_1 = this.ks_X_1;
		X_1_bump = this.ks_X_1_bump;
		Z = this.cs_Z;
		oldZ = this.cs_oldZ;

		for (nonceOfs = 0, i = 0; i < 4; i++, nonceOfs += 4) {
			n = ((int) nonce[nonceOfs] & 0x0ff)
					| (((int) nonce[nonceOfs + 1] & 0x0ff) << 8)
					| (((int) nonce[nonceOfs + 2] & 0x0ff) << 16)
					| (((int) nonce[nonceOfs + 3] & 0x0ff) << 24);

			X_1[i] = X_0[i + 4] + n;
			X_1[i + 4] = X_0[i] + (i - n);
			Z[i] = X_0[i + 3] ^ n;
		}

		X_1[1] += X_1_bump;
		X_1[5] += X_1_bump;
		Z[4] = X_0[7];

		this.cs_aadLen = 0L;
		this.cs_msgLen = 0L;

		Z_0 = Z[0];
		Z_1 = Z[1];
		Z_2 = Z[2];
		Z_3 = Z[3];
		Z_4 = Z[4];

		for (i = 0; i < 8; i++) {
			j = i & 7;

			Z_0 += Z_3;
			Z_3 = Integer.rotateLeft(Z_3, ROT_3b);
			Z_1 += Z_4;
			Z_4 = Integer.rotateLeft(Z_4, ROT_4b);
			Z_2 ^= Z_0;
			Z_0 = Integer.rotateLeft(Z_0, ROT_0a);
			Z_3 ^= Z_1;
			Z_1 = Integer.rotateLeft(Z_1, ROT_1a);
			Z_4 += Z_2;
			Z_2 = Integer.rotateLeft(Z_2, ROT_2a);

			Z_0 ^= Z_3 + X_0[j];
			Z_3 = Integer.rotateLeft(Z_3, ROT_3a);
			Z_1 ^= Z_4;
			Z_4 = Integer.rotateLeft(Z_4, ROT_4a);
			Z_2 += Z_0;
			Z_0 = Integer.rotateLeft(Z_0, ROT_0b);
			Z_3 += Z_1;
			Z_1 = Integer.rotateLeft(Z_1, ROT_1b);
			Z_4 ^= Z_2;
			Z_2 = Integer.rotateLeft(Z_2, ROT_2b);

			Z_0 += Z_3;
			Z_3 = Integer.rotateLeft(Z_3, ROT_3b);
			Z_1 += Z_4;
			Z_4 = Integer.rotateLeft(Z_4, ROT_4b);
			Z_2 ^= Z_0;
			Z_0 = Integer.rotateLeft(Z_0, ROT_0a);
			Z_3 ^= Z_1;
			Z_1 = Integer.rotateLeft(Z_1, ROT_1a);
			Z_4 += Z_2;
			Z_2 = Integer.rotateLeft(Z_2, ROT_2a);

			Z_0 ^= Z_3 + X_1[j] + i;
			Z_3 = Integer.rotateLeft(Z_3, ROT_3a);
			Z_1 ^= Z_4;
			Z_4 = Integer.rotateLeft(Z_4, ROT_4a);
			Z_2 += Z_0;
			Z_0 = Integer.rotateLeft(Z_0, ROT_0b);
			Z_3 += Z_1;
			Z_1 = Integer.rotateLeft(Z_1, ROT_1b);
			Z_4 ^= Z_2;
			Z_2 = Integer.rotateLeft(Z_2, ROT_2b);

			oldZ[i & 3] = Z_4; //Z[OLD_Z_REG];
		}

		Z[0] = Z_0;
		Z[1] = Z_1;
		Z[2] = Z_2;
		Z[3] = Z_3;
		Z[4] = Z_4;

		Z[1] ^= (this.cs_aadXor = AAD_MAGIC_XOR);

		this.cs_i = i;
	}

	public void process(byte[] inbuf, int inbufOfs, byte[] outbuf,
			int outbufOfs, int msgLen) throws IllegalArgumentException {
		int leftOver, endOfs, c, bidx;
		int i, j, ptxt, tmp;
		int[] buckets = this.cache_processbytes_buckets;
		int[] X_0, X_1, oldZ, Z;
		int Z_0, Z_1, Z_2, Z_3, Z_4;

		bidx = this.bucketIdx;
		X_0 = this.ks_X_0;
		X_1 = this.ks_X_1;
		Z = this.cs_Z;
		oldZ = this.cs_oldZ;

		if (0 != (3 & this.cs_msgLen))
			throw new IllegalArgumentException(
					"data misalignment, only the last data chunk "
							+ "can be off a " + PHELIX_DATA_ALIGN
							+ " byte border");

		this.cs_msgLen += (long) msgLen & 0x0ffffffffL;
		i = this.cs_i;
		this.cs_Z[1] ^= this.cs_aadXor;
		this.cs_aadXor = 0;

		Z_0 = Z[0];
		Z_1 = Z[1];
		Z_2 = Z[2];
		Z_3 = Z[3];
		Z_4 = Z[4];

		leftOver = msgLen & 3;
		endOfs = inbufOfs + (msgLen - (int) leftOver);

		for (; inbufOfs < endOfs; i++, inbufOfs += 4, outbufOfs += 4) {
			j = i & 7;

			Z_0 += Z_3;
			Z_3 = Integer.rotateLeft(Z_3, ROT_3b);
			Z_1 += Z_4;
			Z_4 = Integer.rotateLeft(Z_4, ROT_4b);
			Z_2 ^= Z_0;
			Z_0 = Integer.rotateLeft(Z_0, ROT_0a);
			Z_3 ^= Z_1;
			Z_1 = Integer.rotateLeft(Z_1, ROT_1a);
			Z_4 += Z_2;
			Z_2 = Integer.rotateLeft(Z_2, ROT_2a);

			Z_0 ^= Z_3 + X_0[j];
			Z_3 = Integer.rotateLeft(Z_3, ROT_3a);
			Z_1 ^= Z_4;
			Z_4 = Integer.rotateLeft(Z_4, ROT_4a);
			Z_2 += Z_0;
			Z_0 = Integer.rotateLeft(Z_0, ROT_0b);
			Z_3 += Z_1;
			Z_1 = Integer.rotateLeft(Z_1, ROT_1b);
			Z_4 ^= Z_2;
			Z_2 = Integer.rotateLeft(Z_2, ROT_2b);

			buckets[0] = tmp = ((int) inbuf[inbufOfs] & 0x0ff)
					| (((int) inbuf[inbufOfs + 1] & 0x0ff) << 8)
					| (((int) inbuf[inbufOfs + 2] & 0x0ff) << 16)
					| (((int) inbuf[inbufOfs + 3] & 0x0ff) << 24);

			tmp ^= Z_4 + oldZ[i & 3];

			outbuf[outbufOfs] = (byte) tmp;
			outbuf[outbufOfs + 1] = (byte) (tmp >>> 8);
			outbuf[outbufOfs + 2] = (byte) (tmp >>> 16);
			outbuf[outbufOfs + 3] = (byte) (tmp >>> 24);

			buckets[1] = tmp;

			Z_0 += Z_3 ^ buckets[bidx];
			Z_3 = Integer.rotateLeft(Z_3, ROT_3b);
			Z_1 += Z_4;
			Z_4 = Integer.rotateLeft(Z_4, ROT_4b);
			Z_2 ^= Z_0;
			Z_0 = Integer.rotateLeft(Z_0, ROT_0a);
			Z_3 ^= Z_1;
			Z_1 = Integer.rotateLeft(Z_1, ROT_1a);
			Z_4 += Z_2;
			Z_2 = Integer.rotateLeft(Z_2, ROT_2a);

			Z_0 ^= Z_3 + X_1[j] + i;
			Z_3 = Integer.rotateLeft(Z_3, ROT_3a);
			Z_1 ^= Z_4;
			Z_4 = Integer.rotateLeft(Z_4, ROT_4a);
			Z_2 += Z_0;
			Z_0 = Integer.rotateLeft(Z_0, ROT_0b);
			Z_3 += Z_1;
			Z_1 = Integer.rotateLeft(Z_1, ROT_1b);
			Z_4 ^= Z_2;
			Z_2 = Integer.rotateLeft(Z_2, ROT_2b);

			oldZ[i & 3] = Z_4; //Z[OLD_Z_REG];
		}

		if (0 != leftOver) {
			j = i & 7;

			Z_0 += Z_3;
			Z_3 = Integer.rotateLeft(Z_3, ROT_3b);
			Z_1 += Z_4;
			Z_4 = Integer.rotateLeft(Z_4, ROT_4b);
			Z_2 ^= Z_0;
			Z_0 = Integer.rotateLeft(Z_0, ROT_0a);
			Z_3 ^= Z_1;
			Z_1 = Integer.rotateLeft(Z_1, ROT_1a);
			Z_4 += Z_2;
			Z_2 = Integer.rotateLeft(Z_2, ROT_2a);

			Z_0 ^= Z_3 + X_0[j];
			Z_3 = Integer.rotateLeft(Z_3, ROT_3a);
			Z_1 ^= Z_4;
			Z_4 = Integer.rotateLeft(Z_4, ROT_4a);
			Z_2 += Z_0;
			Z_0 = Integer.rotateLeft(Z_0, ROT_0b);
			Z_3 += Z_1;
			Z_1 = Integer.rotateLeft(Z_1, ROT_1b);
			Z_4 ^= Z_2;
			Z_2 = Integer.rotateLeft(Z_2, ROT_2b);

			ptxt = 0; // (jtptc)
			tmp = leftOver << 3;
			for (c = 0; c < tmp; c += 8) {
				ptxt |= ((int) inbuf[inbufOfs++] & 0x0ff) << c;
			}

			buckets[0] = tmp = ptxt;

			tmp ^= Z_4 + oldZ[i & 3];

			buckets[1] = tmp & MASK_LEFTOVER[leftOver];

			for (c = 0; c < leftOver; c++, tmp >>>= 8, outbufOfs++) {
				outbuf[outbufOfs] = (byte) tmp;
			}

			Z_0 += Z_3 ^ buckets[bidx];
			Z_3 = Integer.rotateLeft(Z_3, ROT_3b);
			Z_1 += Z_4;
			Z_4 = Integer.rotateLeft(Z_4, ROT_4b);
			Z_2 ^= Z_0;
			Z_0 = Integer.rotateLeft(Z_0, ROT_0a);
			Z_3 ^= Z_1;
			Z_1 = Integer.rotateLeft(Z_1, ROT_1a);
			Z_4 += Z_2;
			Z_2 = Integer.rotateLeft(Z_2, ROT_2a);

			Z_0 ^= Z_3 + X_1[j] + i;
			Z_3 = Integer.rotateLeft(Z_3, ROT_3a);
			Z_1 ^= Z_4;
			Z_4 = Integer.rotateLeft(Z_4, ROT_4a);
			Z_2 += Z_0;
			Z_0 = Integer.rotateLeft(Z_0, ROT_0b);
			Z_3 += Z_1;
			Z_1 = Integer.rotateLeft(Z_1, ROT_1b);
			Z_4 ^= Z_2;
			Z_2 = Integer.rotateLeft(Z_2, ROT_2b);

			oldZ[i & 3] = Z_4;

			i++;
		}

		Z[0] = Z_0;
		Z[1] = Z_1;
		Z[2] = Z_2;
		Z[3] = Z_3;
		Z[4] = Z_4;

		this.cs_i = i;
	}

	public void processAAD(byte[] aad, int aadOfs, int aadLen)
			throws IllegalArgumentException {
		int c;
		int i, j, ptxt;
		int[] X_0, X_1, oldZ, Z;
		int Z_0, Z_1, Z_2, Z_3, Z_4;

		X_0 = this.ks_X_0;
		X_1 = this.ks_X_1;
		Z = this.cs_Z;
		oldZ = this.cs_oldZ;

		if (0 != (3 & this.cs_aadLen))
			throw new IllegalArgumentException(
					"data misalignment for AAD, only the last data chunk can be off a "
							+ PHELIX_DATA_ALIGN + " byte border");

		this.cs_aadLen += (long) aadLen & 0x0ffffffffL;
		i = this.cs_i;

		Z_0 = Z[0];
		Z_1 = Z[1];
		Z_2 = Z[2];
		Z_3 = Z[3];
		Z_4 = Z[4];

		for (; 0 < aadLen; i++, aadOfs += 4) {
			j = i & 7;

			Z_0 += Z_3;
			Z_3 = Integer.rotateLeft(Z_3, ROT_3b);
			Z_1 += Z_4;
			Z_4 = Integer.rotateLeft(Z_4, ROT_4b);
			Z_2 ^= Z_0;
			Z_0 = Integer.rotateLeft(Z_0, ROT_0a);
			Z_3 ^= Z_1;
			Z_1 = Integer.rotateLeft(Z_1, ROT_1a);
			Z_4 += Z_2;
			Z_2 = Integer.rotateLeft(Z_2, ROT_2a);

			Z_0 ^= Z_3 + X_0[j];
			Z_3 = Integer.rotateLeft(Z_3, ROT_3a);
			Z_1 ^= Z_4;
			Z_4 = Integer.rotateLeft(Z_4, ROT_4a);
			Z_2 += Z_0;
			Z_0 = Integer.rotateLeft(Z_0, ROT_0b);
			Z_3 += Z_1;
			Z_1 = Integer.rotateLeft(Z_1, ROT_1b);
			Z_4 ^= Z_2;
			Z_2 = Integer.rotateLeft(Z_2, ROT_2b);

			if (4 <= aadLen) {
				ptxt = ((int) aad[aadOfs] & 0x0ff)
						| (((int) aad[aadOfs + 1] & 0x0ff) << 8)
						| (((int) aad[aadOfs + 2] & 0x0ff) << 16)
						| (((int) aad[aadOfs + 3] & 0x0ff) << 24);
				aadLen -= 4;
			} else {
				ptxt = 0; // (jtptc)

				aadLen <<= 3;
				for (c = 0; c < aadLen; c += 8) {
					ptxt |= ((int) aad[aadOfs++] & 0x0ff) << c;
				}
				aadLen = 0;
			}

			Z_0 += Z_3 ^ ptxt;
			Z_3 = Integer.rotateLeft(Z_3, ROT_3b);
			Z_1 += Z_4;
			Z_4 = Integer.rotateLeft(Z_4, ROT_4b);
			Z_2 ^= Z_0;
			Z_0 = Integer.rotateLeft(Z_0, ROT_0a);
			Z_3 ^= Z_1;
			Z_1 = Integer.rotateLeft(Z_1, ROT_1a);
			Z_4 += Z_2;
			Z_2 = Integer.rotateLeft(Z_2, ROT_2a);

			Z_0 ^= Z_3 + X_1[j] + i;
			Z_3 = Integer.rotateLeft(Z_3, ROT_3a);
			Z_1 ^= Z_4;
			Z_4 = Integer.rotateLeft(Z_4, ROT_4a);
			Z_2 += Z_0;
			Z_0 = Integer.rotateLeft(Z_0, ROT_0b);
			Z_3 += Z_1;
			Z_1 = Integer.rotateLeft(Z_1, ROT_1b);
			Z_4 ^= Z_2;
			Z_2 = Integer.rotateLeft(Z_2, ROT_2b);

			oldZ[i & 3] = Z_4;
		}

		Z[0] = Z_0;
		Z[1] = Z_1;
		Z[2] = Z_2;
		Z[3] = Z_3;
		Z[4] = Z_4;

		this.cs_i = i;
	}

	public void finalize(byte[] mac, int macOfs) {
		int c, end;
		int i, j, k, t, ptxt;
		int[] Z, X_0, X_1, oldZ;
		int Z_0, Z_1, Z_2, Z_3, Z_4;
		int[] tmp = this.cache_finalize_tmp;

		X_0 = this.ks_X_0;
		X_1 = this.ks_X_1;
		Z = this.cs_Z;
		oldZ = this.cs_oldZ;

		i = this.cs_i;
		ptxt = (int) this.cs_msgLen & 3;

		Z_0 = Z[0];
		Z_1 = Z[1];
		Z_2 = Z[2];
		Z_3 = Z[3];
		Z_4 = Z[4];

		Z_0 ^= MAC_MAGIC_XOR;
		Z_4 ^= this.cs_aadLen;
		Z_2 ^= this.cs_aadLen >>> 32;
		Z_1 ^= this.cs_aadXor;

		for (k = 0; k < tmp.length; k++, i++) {
			j = i & 7;

			Z_0 += Z_3;
			Z_3 = Integer.rotateLeft(Z_3, ROT_3b);
			Z_1 += Z_4;
			Z_4 = Integer.rotateLeft(Z_4, ROT_4b);
			Z_2 ^= Z_0;
			Z_0 = Integer.rotateLeft(Z_0, ROT_0a);
			Z_3 ^= Z_1;
			Z_1 = Integer.rotateLeft(Z_1, ROT_1a);
			Z_4 += Z_2;
			Z_2 = Integer.rotateLeft(Z_2, ROT_2a);

			Z_0 ^= Z_3 + X_0[j];
			Z_3 = Integer.rotateLeft(Z_3, ROT_3a);
			Z_1 ^= Z_4;
			Z_4 = Integer.rotateLeft(Z_4, ROT_4a);
			Z_2 += Z_0;
			Z_0 = Integer.rotateLeft(Z_0, ROT_0b);
			Z_3 += Z_1;
			Z_1 = Integer.rotateLeft(Z_1, ROT_1b);
			Z_4 ^= Z_2;
			Z_2 = Integer.rotateLeft(Z_2, ROT_2b);

			tmp[k] = ptxt ^ (Z_4 + oldZ[i & 3]);

			Z_0 += Z_3 ^ ptxt;
			Z_3 = Integer.rotateLeft(Z_3, ROT_3b);
			Z_1 += Z_4;
			Z_4 = Integer.rotateLeft(Z_4, ROT_4b);
			Z_2 ^= Z_0;
			Z_0 = Integer.rotateLeft(Z_0, ROT_0a);
			Z_3 ^= Z_1;
			Z_1 = Integer.rotateLeft(Z_1, ROT_1a);
			Z_4 += Z_2;
			Z_2 = Integer.rotateLeft(Z_2, ROT_2a);

			Z_0 ^= Z_3 + X_1[j] + i;
			Z_3 = Integer.rotateLeft(Z_3, ROT_3a);
			Z_1 ^= Z_4;
			Z_4 = Integer.rotateLeft(Z_4, ROT_4a);
			Z_2 += Z_0;
			Z_0 = Integer.rotateLeft(Z_0, ROT_0b);
			Z_3 += Z_1;
			Z_1 = Integer.rotateLeft(Z_1, ROT_1b);
			Z_4 ^= Z_2;
			Z_2 = Integer.rotateLeft(Z_2, ROT_2b);

			oldZ[i & 3] = Z_4;
		}

		c = end = MAC_INIT_CNT;
		end += (96 == this.ks_macSize) ? 3 : 4;

		while (c < end) {
			t = tmp[c++];
			mac[macOfs++] = (byte) t;
			mac[macOfs++] = (byte) (t >>> 8);
			mac[macOfs++] = (byte) (t >>> 16);
			mac[macOfs++] = (byte) (t >>> 24);
		}
	}
}
